﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Net;
using System.Net.NetworkInformation;

namespace NetMonitor.Server
{
    public class NetPoint
    {
        public NetPoint()
        {
            pingClient = new Ping();
            pingClient.PingCompleted += new PingCompletedEventHandler(pingClient_PingCompleted);
        }

        #region 属性

        private string id;        
        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        private int pointtype;
        public int PointType
        {
            get { return pointtype; }
            set { pointtype = value; }
        }

        private int imggroup;
        public int ImgGroup
        {
            get { return imggroup; }
            set { imggroup = value; }
        }

        private string neighbors;
        public string Neighbors
        {
            get { return neighbors; }
            set { neighbors = value; }
        }

        private string pointName;
        /// <summary>
        /// 节点的名称
        /// </summary>
        public string PointName
        {
            get { return pointName; }
            set { pointName = value; }
        }


        private string pointLocation;
        /// <summary>
        /// 节点的地理位置
        /// </summary>
        public string PointLocation
        {
            get { return pointLocation; }
            set { pointLocation = value; }
        }


        private IPAddress pointIpaddress;
        /// <summary>
        /// 节点的IP地址
        /// </summary>
        public IPAddress PointIpaddress
        {
            get { return pointIpaddress; }
            set { pointIpaddress = value; }
        }

        private Point pointPosition;
        /// <summary>
        /// 节点的X,Y坐标点
        /// </summary>
        public Point PointPosition
        {
            get { return pointPosition; }
            set { pointPosition = value; }
        }

        private string customStatus;
        public string CustomStatus
        {
            get { return customStatus; }
            set { customStatus = value; }
        }

        #endregion
        

        #region 有关测试网络联通的方法

        // lryh ping忙标志（有一个Ping未返回）
        private bool isBusy = false;

        // lryh 丢包率
        private double dropRate = 0;

        // lryh 连通状态标志
        private string connectivity = CONNECTIVITY_ALARM;
        public string Connectivity
        {
            get 
            {
                if (customStatus != null)
                    return customStatus;
                else
                    return connectivity; 
            }
            // set { connectivity = value; }
        }

        private void changeState(string value)
        {
            connectivity = value;
            if (value == CONNECTIVITY_ALARM)
                logToDb(false);
            else if (value == CONNECTIVITY_NORMAL)
                logToDb(true);
        }

        private string insertSql = "insert into NodeEvent (pointid, ipaddress, status, logtime) "
                                 + "values (@p0, @p1, @p2, GetDate())";

        private void logToDb(bool up)
        {
            try
            {
                using (DataClasses1DataContext dc = new DataClasses1DataContext())
                {
                    dc.ExecuteCommand(insertSql, ID, PointIpaddress.ToString(), up ? "up" : "down");
                }
            }
            catch (Exception e)
            {
                System.Console.Out.WriteLine(e.Message);
                System.Console.Out.WriteLine(e.StackTrace);
            }
        }

        // lryh 短期历史记录
        private Queue<bool> queuePingLog = new Queue<bool>();
        
        // lryh 记录保存数量
        private const int QUEUE_PING_LOG_SIZE = 10;
        
        // lryh 状态变换丢包率阈值
        private const double DROP_RATE_ENTER_WARNING = 0.5;
        private const double DROP_RATE_ENTER_ALARM = 0.9;
        private const double DROP_RATE_QUIT_WARNING = 0.2;
        private const double DROP_RATE_QUIT_ALARM = 0.5;
        
        // lryh 连通状态
        public const string CONNECTIVITY_NORMAL = "normal";
        public const string CONNECTIVITY_WARNING = "warning";
        public const string CONNECTIVITY_ALARM = "alarm";

        private int count = 0;

        // lryh 添加记录，更新丢包率
        private void addPingEntry(bool value)
        {
            if (queuePingLog.Count == QUEUE_PING_LOG_SIZE)
            {
                queuePingLog.Dequeue();
                queuePingLog.Enqueue(value);
            }
            else
                queuePingLog.Enqueue(value);

            // lryh 计算丢包率
            bool[] dropLog = queuePingLog.ToArray();
            int drops = 0;
            for (int i = 0; i < dropLog.Length; i++)
            {
                if (dropLog[i])
                    drops++;
            }
            dropRate = (double)drops / (double)dropLog.Length;

            // lryh 转换状态
            if (connectivity == CONNECTIVITY_NORMAL)
            {
                if (dropRate > DROP_RATE_ENTER_WARNING)
                    changeState(CONNECTIVITY_WARNING);
            }
            else if (connectivity == CONNECTIVITY_WARNING)
            {
                if (dropRate >= DROP_RATE_ENTER_ALARM)
                    changeState(CONNECTIVITY_ALARM);
                else if (dropRate <= DROP_RATE_QUIT_WARNING)
                    changeState(CONNECTIVITY_NORMAL);
            }
            else if (connectivity == CONNECTIVITY_ALARM)
            {
                if (dropRate <= DROP_RATE_QUIT_ALARM)
                    changeState(CONNECTIVITY_WARNING);
            }

            if (count < 10)
                if (++count == 10 && connectivity.Equals(CONNECTIVITY_ALARM))
                    changeState(connectivity);


            Console.Out.WriteLine(pointName + "(" + pointIpaddress.ToString() + ") : " + connectivity + " (" + dropRate + ")");
        }

        /// <summary>
        /// 开始ping
        /// </summary>
        public void StartPing()
        {            
            // lryh 前一个ping未返回前不再新ping
            if (pointIpaddress != null && !isBusy)
            {
                pingClient.SendAsync(pointIpaddress, null);
                isBusy = true;
            }         
        }

        private Ping pingClient;

        /// <summary>
        /// 停止ping
        /// </summary>
        public void StopPing()
        {
            pingClient.SendAsyncCancel();
        }

        /// <summary>
        /// ICMP检测代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pingClient_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            //检测未出错情况下
            if (e.Error == null)
                if (e.Cancelled)
                {
                    //如果点击"取消"相应语句
                    System.Console.Out.WriteLine("用户取消了连通性测试");
                    return;
                }
                else                
                    if (e.Reply.Status == IPStatus.Success)                    
                        // lryh 添加未丢包记录
                        addPingEntry(false);                    
                    else                                        
                        // lryh 添加丢包记录
                        addPingEntry(true);                                    
            else            
                // 检测出错的情况下           
                System.Console.Out.WriteLine("An error occurred while sending this ping. " + e.Error.InnerException.Message);                        

            // lryh 一个ping完成后清空忙标志
            isBusy = false;
        }

        #endregion

    }
}
